package com.smart.common.utils;

import com.smart.common.constant.Constants;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.codec.binary.Base64;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 图片处理工具类
 *
 * @author pst
 */
public class ImageUtils
{
    private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);

    /**
     * 将图片转换成Base64编码
     * @param imgFile 待处理图片地址
     * @return
     */
    public static String getImgBase(String imgFile) throws IOException {

        // 将图片文件转化为二进制流
        InputStream in = null;
        byte[] data = null;
        // 读取图片字节数组
        in = new FileInputStream(imgFile);
        data = new byte[in.available()];
        in.read(data);
        in.close();
        // 图片头
        //String imghead = "data:image/jpeg;base64,";
        return Base64.encodeBase64String(data);
    }

    /**
     * 请求调用方法
     * gb
     *
     * @param fromPath1 byte直接文件图片
     * @return 剪切后的byte文件
     */
    public static byte[] imageSet(byte[] fromPath1) throws Exception {
        return imageChangeSize(fromPath1, 470, 635);
    }

    /**
     * @param data   byte类型图片
     * @param max_wi 图片修改后最大的宽
     * @param max_he 图片修改后最大的高
     * @return
     * @throws Exception
     * @Description 更改图片内容的大小 byte【】 类型
     */
    public static byte[] imageChangeSize(byte[] data, int max_wi, int max_he) throws Exception {
        ImageIO io = null;
        float rate = 1;
        /*图片的原始宽 120*/
        int oldwi;
        /*图片的原始高 120*/
        int oldhe;
        /*图片修改后的宽 0*/
        int new_wi = 0;
        /*图片修改后的高 0*/
        int new_he = 0;
        /*拿到byte图片*/
        InputStream is = new ByteArrayInputStream(data);
        BufferedImage bufImg = ImageIO.read(is);
        /*图片的原始宽度*/
        oldwi = bufImg.getWidth();
        /*图片的原始高度*/
        oldhe = bufImg.getHeight();
        //
        rate = (float) oldwi / (float) oldhe;
        /*如果图片的原宽大于最大宽度，并且原高小于等于最大高度。则证明图片过宽了，将图片宽度设置为最大宽度，此时需要等比例减小高度*/
        if (oldwi > max_wi && oldhe <= max_he) {
            new_wi = max_wi;
            new_he = new Float((float) new_wi / rate).intValue();
            /*如果图片的原宽和原高都大于或者都小于其所对应的最大值，则以任意一方为主(此处以最大高度为主)*/
        } else if (oldwi >= max_wi && oldhe >= max_he || oldwi <= max_wi && oldhe <= max_he) {
            new_he = max_he;
            new_wi = new Float(new_he * rate).intValue();
            /*如果图片的原宽小于于最大宽度，并且原高大于等于最大高度。则证明图片过高了，将图片宽度设置为最大高度，此时需要等比例减小宽度*/
        } else if (oldwi <= max_wi && oldhe > max_he) {
            new_he = max_he;
            new_wi = new Float(new_he * rate).intValue();
        }
//        System.err.println("原宽度：" + oldwi + "原高度：" + oldhe + "_" + rate);
        /*开始改变大小*/
        ImageObserver ser = null;
        BufferedImage bf = new BufferedImage(new_wi, new_he, BufferedImage.TYPE_INT_RGB);
        bf.getGraphics().drawImage(bufImg, 0, 0, new_wi, new_he, null);
//        System.err.println("新宽度：" + bf.getWidth() + "-" + "新高度：" + bf.getHeight());
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        //转换编码格式JPEG
        ImageIO.write(bf, "jpeg", out);
        byte[] re = out.toByteArray();
        //logger.info("【图片剪切】| 图片原大小={}kb | 压缩后大小={}kb", (data.length / 1024), (re.length / 1024));
        return re;
    }


    /**
     * [压缩要上传的文件，并将文件类型转为指定的文件类型集合中的一个。]
     *
     * @param file         要上传的文件
     * @param absolutePath 临时文件的绝对路径
     * @return
     */
    public static MultipartFile compressFile(MultipartFile file, String absolutePath) throws IOException {
        List<String> fileTypeList = new ArrayList<>();
        fileTypeList.add("jpg");
        fileTypeList.add("png");
        fileTypeList.add("bmp");
        fileTypeList.add("jpeg");
        fileTypeList.add("PNG");
        fileTypeList.add("JPG");
        fileTypeList.add("BMP");
        fileTypeList.add("JPEG");
        //记录原MultipartFile，如果压缩异常就用原来的MultipartFile
        MultipartFile oldMultipartFile = file;
        FileInputStream fileInputStream = null;
        try {
            String fileName = file.getName();
            String originalFilename = file.getOriginalFilename();
            String contentType = file.getContentType();
            //获取要上传的文件后缀
            String fileExt = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            File tempFile = new File(absolutePath);
            if (fileTypeList.contains(fileExt)) {
                //如果文件类型符合，则只压缩就好了
                Thumbnails.of(file.getInputStream())
                        .scale(1f)
                        .outputQuality(0.2f)
                        .toFile(tempFile);
            } else {
                //如果文件类型不在指定的集合内。则要转格式，并压缩
                Thumbnails.of(file.getInputStream())
                        .scale(1f)
                        .outputFormat(fileTypeList.get(0))
                        .outputQuality(0.2f)
                        .toFile(tempFile);
                originalFilename = originalFilename.replace("." + fileExt, "." + fileTypeList.get(0));
            }
            fileInputStream = new FileInputStream(tempFile);
            file = new MockMultipartFile(fileName, originalFilename, contentType, fileInputStream);
            //boolean success = tempFile.delete();
            //log.info("删除临时file success：{}", success);
        } catch (IOException e) {
            log.error("压缩图片失败,把MultipartFile赋值为原来的值oldFile,exception：{}", e);
            file = oldMultipartFile;
        } finally {
            fileInputStream.close();
            fileTypeList.clear();
        }
        return file;
    }

    //public static void main(String[] args) throws IOException {
    //    byte[] bytes = FileUtils.readFileToByteArray(new File("C:\\Users\\Administrator\\Desktop\\邓111111.jpg"));
    //    long l = System.currentTimeMillis();
    //    bytes = compressPicForScale(bytes, 300, "x");// 图片小于300kb
    //    System.out.println(System.currentTimeMillis() - l);
    //    FileUtils.writeByteArrayToFile(new File("C:\\Users\\Administrator\\Desktop\\邓11111压缩后.jpg"), bytes);
    //}

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            //log.info("【图片压缩】| 图片原大小={}kb | 压缩后大小={}kb",srcSize / 1024, imageBytes.length / 1024);
        } catch (Exception e) {
            log.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }

    //byte数组到图片
    public static void byte2image(byte[] data,String path){
        if(data.length<3||path.equals("")) return;
        try{
            FileImageOutputStream imageOutput = new FileImageOutputStream(new File(path));
            imageOutput.write(data, 0, data.length);
            imageOutput.close();
            //System.out.println("Make Picture success,Please find image in " + path);
        } catch(Exception ex) {
            //System.out.println("Exception: " + ex);
            ex.printStackTrace();
        }
    }

    /**
     * byte[]数组转File
     *
     * @param bytes
     * @param fileFullPath
     * @return
     */
    public static File byte2file(byte[] bytes, String fileFullPath) {
        if (bytes == null) {
            return null;
        }
        FileOutputStream fileOutputStream = null;
        try {
            File file = new File(fileFullPath);
            //判断文件是否存在
            if (file.exists()) {
                file.mkdirs();
            }
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                }  catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }
        return null;
    }
}
